package com.htd.htdapmservice.service.impl;

import com.htd.htdapmdmo.LogAnalyzeErrorRecord;
import com.htd.htdapmdmo.OneAlertFilterKey;
import com.htd.htdapmdmo.OneAlertKey;
import com.htd.htdapmservice.service.intf.ElasticsearchService;
import com.htd.htdapmservice.service.intf.LogAnalyzeErrorRecordService;
import com.htd.htdapmservice.service.intf.OneAlertFilterKeyService;
import com.htd.htdapmservice.service.intf.OneAlertKeyService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.admin.indices.get.GetIndexResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class ElasticsearchServiceImpl implements ElasticsearchService {

    private static final Logger LOGGER = LoggerFactory.getLogger(OneAlertServiceImpl.class);

    @Resource
    private TransportClient client;
    @Autowired
    LogAnalyzeErrorRecordService logAnalyzeErrorRecordService;

  
    private final static int MESSAGE_LENGTH = 800;
    private final static String FILTER_TYPE_OR = "OR";
    private final static String FILTER_TYPE_NOT = "NOT";

    @Value("${elasticsearch.search.time}")
    private int time;

    @Autowired
    private OneAlertKeyService oneAlertKeyService;

    @Autowired
    private OneAlertFilterKeyService oneAlertFilterKeyService;

    @Override
    public List<LogAnalyzeErrorRecord> getNewLogAnalyzeErrorRecordList() {
        List<LogAnalyzeErrorRecord> logAnalyzeErrorRecords = new ArrayList<>();
        List<Map<String, Object>> results = this.getWarningMsg();
        if (CollectionUtils.isEmpty(results)) {
            LOGGER.info("ElasticsearchServiceImpl.getWarningMsg 没有查询到数据 ");
            return logAnalyzeErrorRecords;
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
        try {
            List<OneAlertKey> oneAlertKeyList = oneAlertKeyService.findOneAlertKeyList();
            for (int i = 0; i < results.size(); i++) {
                Map<String, Object> result = results.get(i);
                LogAnalyzeErrorRecord logAnalyzeErrorRecord = new LogAnalyzeErrorRecord();
                logAnalyzeErrorRecord.setAlarmsTitle("告警_" + result.get("index").toString());
                String message = (String) result.get("message");
                message = getMessage(message);
                logAnalyzeErrorRecord.setAlarmsDetail(message);
                logAnalyzeErrorRecord.setCreateTime(new Date());
                logAnalyzeErrorRecord.setUpdateTime(new Date());
                String index = result.get("index").toString();
                index = index.substring(0, index.lastIndexOf("-")).toUpperCase();
                for (OneAlertKey oneAlertKey : oneAlertKeyList) {
                    if (index.equals(oneAlertKey.getProductIndex())) {
                        logAnalyzeErrorRecord.setProductTypeCode(oneAlertKey.getProductCode());
                        break;
                    }
                }
                if(StringUtils.isEmpty(logAnalyzeErrorRecord.getProductTypeCode())){
                	LOGGER.info("index:{} 未找到匹配的productCode",index);
                	continue;
                }
                logAnalyzeErrorRecord.setLogSource(result.get("source").toString());
                Date date = sdf.parse(result.get("@timestamp").toString());
                logAnalyzeErrorRecord.setHappenTime(date);
                if (StringUtils.isNotEmpty(message.trim())) {
                    logAnalyzeErrorRecords.add(logAnalyzeErrorRecord);
                }
            }
        } catch (Exception e) {
            LOGGER.error("getNewLogAnalyzeErrorRecordList查询异常：{}", e.getMessage());
        }
        return logAnalyzeErrorRecords;
    }


    /**
     * 获取异常信息
     *
     * @param
     * @return
     */
    private List<Map<String, Object>> getWarningMsg() {
        List<String> indexs = this.getTodayIndexs();
        List<Map<String, Object>> results = new ArrayList<Map<String, Object>>();
        List<OneAlertFilterKey> oneAlertFilterKeyListOr = oneAlertFilterKeyService.findOneAlertFilterKeyListByType(FILTER_TYPE_OR);
        List<OneAlertFilterKey> oneAlertFilterKeyListNot = oneAlertFilterKeyService.findOneAlertFilterKeyListByType(FILTER_TYPE_NOT);
        QueryBuilder queryBuilder = getQueryBuilder(oneAlertFilterKeyListOr, oneAlertFilterKeyListNot);
        for (int i = 0; i < indexs.size(); i++) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
            String date2 = sdf.format(new Date());
            if (date2.equals(indexs.get(i).substring(indexs.get(i).lastIndexOf("-") + 1))) {
                try {
                    List<Map<String, Object>> result = getErrorMsg(indexs.get(i), queryBuilder);
                    if (result.size() > 0) {
                        results.addAll(result);
                    }
                } catch (Exception e) {
                    LOGGER.error(e.getMessage());
                }
            }
        }
        return results;
    }

    /**
     * 组装查询条件
     * @param oneAlertFilterKeyListOr
     * @param oneAlertFilterKeyListNot
     * @return
     */
    private QueryBuilder getQueryBuilder(List<OneAlertFilterKey> oneAlertFilterKeyListOr,
                                         List<OneAlertFilterKey> oneAlertFilterKeyListNot){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
        Calendar calendar = Calendar.getInstance();
        //当前时间的前8个小时
        calendar.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY) - 8);
        String endDate = simpleDateFormat.format(calendar.getTime());
        long currentTime = System.currentTimeMillis();
        //当前时间的前8个小时+time分钟
        currentTime =currentTime-(480+time)*60*1000;
        Date date = new Date(currentTime);
        String beginDate = simpleDateFormat.format(date);
        BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();
        for (int i=0;i<oneAlertFilterKeyListOr.size();i++){
            //should 相当于or
            if(isContainChinese(oneAlertFilterKeyListOr.get(i).getFilterKey())){
                boolBuilder.should(QueryBuilders.termQuery("message", oneAlertFilterKeyListOr.get(i).getFilterKey()));
            } else {
                boolBuilder.should(QueryBuilders.matchQuery("message", oneAlertFilterKeyListOr.get(i).getFilterKey()));
            }
        }
        BoolQueryBuilder finBuilder = QueryBuilders.boolQuery();
        for (OneAlertFilterKey oneAlertFilterKey : oneAlertFilterKeyListNot) {
            finBuilder.mustNot(QueryBuilders.matchPhraseQuery("message", oneAlertFilterKey.getFilterKey()));
        }
        finBuilder.filter(QueryBuilders.rangeQuery("@timestamp").from(beginDate).to(endDate));
        finBuilder.must(boolBuilder);
        return finBuilder;
    }

    private List<Map<String, Object>> getErrorMsg(String indexs,
                                                  QueryBuilder queryBuilder) throws ParseException {
        String type = "doc";
        SearchRequestBuilder builder = this.client.prepareSearch(indexs)
                .setTypes(type)
                .setSearchType(SearchType.QUERY_THEN_FETCH)
                .setQuery(queryBuilder);
        //通过from和size参数进行分页。From定义查询结果开始位置，size定义返回的hits（一条hit对应一条记录）最大数量。
//                .setFrom(0)
//                .setSize(10);
        SearchResponse response = builder.get();

        List<Map<String, Object>> result = new ArrayList<>();
        SearchHits hits = response.getHits();
        for (SearchHit hit : hits) {
            Map<String, Object> source = hit.getSourceAsMap();
            source.put("index", hit.getIndex());
            result.add(source);
        }
        return result;
    }

    /**
     * 判断字符串中是否包含中文
     * @param str
     * 待校验字符串
     * @return 是否为中文
     * @warn 不能校验是否为中文标点符号
     */
    public static boolean isContainChinese(String str) {
        Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
        Matcher m = p.matcher(str);
        if (m.find()) {
            return true;
        }
        return false;
    }

    /**
     * 获取所有index
     *
     * @return
     */
    private String[] getAllIndexs() {
        GetIndexResponse resp = client.admin().indices().prepareGetIndex().execute().actionGet();
        String[] indexnames = resp.getIndices();
        return indexnames;
    }


    /**
     * 获取今天的所有index
     *
     * @return
     */
    private List<String> getTodayIndexs() {
        GetIndexResponse resp = client.admin().indices().prepareGetIndex().execute().actionGet();
        String[] indexnames = resp.getIndices();
        List<String> indexs = new ArrayList<>();
        for (int i = 0; i < indexnames.length; i++) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd");
            String date2 = sdf.format(new Date());
            if (date2.equals(indexnames[i].substring(indexnames[i].lastIndexOf("-") + 1))) {
                indexs.add(indexnames[i]);
            }
        }
        return indexs;
    }


    private String getMessage(String message) {
        if (message.length() > MESSAGE_LENGTH) {
            List<OneAlertFilterKey> oneAlertFilterKeyListOr = oneAlertFilterKeyService.findOneAlertFilterKeyListByType(FILTER_TYPE_OR);
            for (OneAlertFilterKey oneAlertFilterKey : oneAlertFilterKeyListOr) {
                if (message.indexOf(oneAlertFilterKey.getFilterKey()) > 0) {
                    if (message.length() - message.indexOf(oneAlertFilterKey.getFilterKey()) > MESSAGE_LENGTH) {
                        message = message.substring(message.indexOf(oneAlertFilterKey.getFilterKey()), message.indexOf(oneAlertFilterKey.getFilterKey()) + MESSAGE_LENGTH);
                        break;
                    } else {
                        message = message.substring(message.indexOf(oneAlertFilterKey.getFilterKey()));
                        break;
                    }
                }
            }
        }
        return message;
    }
}
